package com.hqyj.springBoot.modules.account.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hqyj.springBoot.modules.account.dao.UserDao;
import com.hqyj.springBoot.modules.account.dao.UserRoleDao;
import com.hqyj.springBoot.modules.account.entity.User;
import com.hqyj.springBoot.modules.account.entity.UserRole;
import com.hqyj.springBoot.modules.account.service.UserService;
import com.hqyj.springBoot.modules.common.entity.ResultEntity;
import com.hqyj.springBoot.modules.common.entity.SearchBean;
import com.hqyj.springBoot.util.MD5Util;
import com.hqyj.springBoot.util.RedisUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;


@Service
public class UserServiceImpl implements UserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RedisUtils redisUtils;
    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName,password);
    }

    @Override
    public ResultEntity<User> login(User user) {
        //根据登录失败判断账号是否为锁定状态
        //将输入失败的次数存入Redis
        String redisKey = String.format("login_fail_count_%s",user.getUserName());
        int loginFailMax = 5;//设置登录失败的最大次数
        int loginFailCount = redisUtils.get(redisKey) == null ? 0 : (int) redisUtils.get(redisKey);//这里第一次取的值为空
        if(loginFailCount >= loginFailMax){
            return new ResultEntity<>(
                    ResultEntity.ResultStatus.FAILED.status,
                    String.format("该账户已经连续登录失败 %d 次 ，锁定账户30秒！",loginFailCount));
        }
        //Shiro逻辑下的登录流程
        //1、获得应用层与Shiro框架交互的组件Subject
        Subject subject = SecurityUtils.getSubject();
        //2、 根据 用户名 密码 封装令牌
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),MD5Util.getMD5(user.getPassword()));
        token.setRememberMe(user.isRememberMe());
        try{
            subject.login(token);
            //3、检查用户所拥有的角色
            subject.checkRoles();

            //为了得到用户的ID我们要从subject组件中获取session
            Session session = subject.getSession();
            //这里所得到的凭证是在Realm中获得的全部用户信息
            session.setAttribute("user",subject.getPrincipal());
            //的登录成功的时候将前几次的错误清空
            redisUtils.delete(redisKey);
        }catch (Exception e){
            LOGGER.debug(e.getMessage());
            //登陆失败增加失败次数
            redisUtils.increment(redisKey,1);
            loginFailCount += 1;
            if(loginFailCount < loginFailMax){
                return new ResultEntity<>(
                        ResultEntity.ResultStatus.FAILED.status,
                        String.format("该账户已经连续登录失败 %d 次 ，还剩 %d 次！",loginFailCount,(loginFailMax - loginFailCount)));
            } else {
                redisUtils.expire(redisKey,30);
                return new ResultEntity<>(
                        ResultEntity.ResultStatus.FAILED.status,
                        String.format("该账户已经连续登录失败超过 %d 次 ，锁定账户30秒！",loginFailMax));
            }

//            return new ResultEntity<>(ResultEntity.ResultStatus.FAILED.status,"用户名或密码错误！");
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"登录成功！");
    }

    @Override
    public ResultEntity<User> addUser(User user) {
        //判断用户名是否重复
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "用户名或邮箱重复！");
        }
        user.setCreateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.addUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.addtUserRole(new UserRole(user.getId(), item.getId()));});
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"添加成功！",user);
    }

    @Override
    public ResultEntity<User> updateUserByUser(User user) {
        //判断用户名是否重复
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        //if(users.size() > 0 && users.get(0).getId() != user.getId())
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "用户名或邮箱重复！");
        }
        userDao.updateUserByUser(user);
        // 当前端设置新的角色信息时
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            // 根据用户 id，删除已有的角色信息
            userRoleDao.deleteUserRoleByUserId(user.getId());
            // 插入新的角色信息
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.addtUserRole(new UserRole(user.getId(), item.getId()));});
        }
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"修改成功！",user);
    }

    @Override
    public ResultEntity<User> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.status,"删除成功！");
    }

    @Override
    public User selectUserById(int id) {
        return userDao.selectUserById(id);
    }

    @Override
    public PageInfo<User> selectAllUser(SearchBean searchBean) {
        searchBean.initSearchBean();
        PageHelper.startPage(searchBean.getCurrentPage(),searchBean.getPageSize());
        return new PageInfo<User>(Optional.ofNullable(userDao.SelectAllUserInPage(searchBean)).orElse(Collections.emptyList()));
    }

    @Override
    public User selectUserByUserName(String userName) {
        return userDao.selectUserByUserName(userName);
    }

    @Override
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }
}
